//
//  QLRainURLProtocol.m
//  aa
//
//  Created by 周正华 on 2018/8/21.
//  Copyright © 2018年 前隆金融. All rights reserved.
//

#import "QLRainURLProtocol.h"

static const NSString *fileUrlProtocolNameKey = @"fileUrlProtocolNameKey";
static const NSString *fileUrlProtocolRecodeTimeKey = @"fileUrlProtocolRecodeTimeKey";
static const long sexSeconds = 6;//超过6秒做记录

@interface UrlProtocolManager:NSObject
@property (nonatomic, strong)NSMutableDictionary <NSString *,NSDictionary*>*requestDictionary;//存储请求标识
@property (nonatomic, assign)NSInteger requestTag;
@property (nonatomic, strong) dispatch_source_t timer;
@end

@implementation UrlProtocolManager
+ (instancetype)shareUrlProtocolManager {
    static UrlProtocolManager *shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstance = [[UrlProtocolManager alloc]init];
    });
    return shareInstance;
}
-(instancetype)init {
    self = [super init];
    if (self) {
        self.requestDictionary = @{}.mutableCopy;
        self.requestTag = 0;
        [self createTimer];
    }
    return self;
}

//启动计时器
- (void)createTimer {
    NSLog(@"%s",__FUNCTION__);
    NSInteger timeout = 7;//7秒执行一次
    //获取全局队列
    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //创建一个定时器，并将定时器的任务交给全局队列执行(并行，不会造成主线程阻塞)
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, global);
    
    // 设置触发的间隔时间
    dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //timeout * NSEC_PER_SEC  代表设置定时器触发的时间间隔为timeout s
    //0 * NSEC_PER_SEC    代表时间允许的误差是 0s
    __weak typeof(self)weakSelf = self;
    dispatch_source_set_event_handler(_timer, ^{
        NSLog(@"start timer");
        NSMutableString *resultStr = @"".mutableCopy;
        NSArray *allKeys = weakSelf.requestDictionary.allKeys;
        NSInteger allKeyCount = allKeys.count;
        if (allKeyCount > 0) {
            for (NSInteger i = 0; i < allKeyCount; i ++) {
                NSString *dicKey = allKeys[i];
                NSDictionary *dic = [weakSelf.requestDictionary objectForKey:dicKey];
                if (dic != nil) {
                    NSNumber *timeMarkLong = [dic objectForKey:fileUrlProtocolRecodeTimeKey];
                    NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
                    if (currentTime - [timeMarkLong longValue] >= sexSeconds ) {
                        NSString *fileName = [dic objectForKey:fileUrlProtocolNameKey];
                        [resultStr appendFormat:@"%@_",fileName];
                        [weakSelf.requestDictionary removeObjectForKey:dicKey];//监控到的key记录之后就移除掉
                    }
                }
                
            }
            NSLog(@"resultStr is \n%@",resultStr);
        }
        
    });
    
    dispatch_resume(_timer);
    
}

- (void)addRequestWithRemarkKey:(NSString *)remarkKey andFileName:(NSString *)fileName {
    NSTimeInterval timeMark = [[NSDate date] timeIntervalSince1970];
    NSDictionary *fileDic = @{
                              fileUrlProtocolNameKey:fileName,
                              fileUrlProtocolRecodeTimeKey:@(timeMark)
                              };
    [[UrlProtocolManager shareUrlProtocolManager].requestDictionary setObject:fileDic forKey:remarkKey];
}

- (void)removeRequestWithRemarkKey:(NSString *)remarkKey {
    [[UrlProtocolManager shareUrlProtocolManager].requestDictionary removeObjectForKey:remarkKey];
}

- (void)destroyTimer {
    dispatch_source_cancel(_timer);
}

@end

static NSString *rainMarkKey = @"TravinProtocolHandledKey";

@interface QLRainURLProtocol()
@property(nonatomic, strong)NSURLConnection *connection;
@property(nonatomic, strong)NSString *remarkKey;//记录当前请求的标记key
@end

@implementation QLRainURLProtocol



//对js文件做监控
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    
    NSString * urlstring = [request.URL absoluteString];
    
    if ([urlstring containsString:@".js"]) {
        //看看是否已经处理过了，防止无限循环
        if ([NSURLProtocol propertyForKey:rainMarkKey inRequest:request]) {
            return NO;
        }
        return YES;
    }
    return NO;
}
//我们可以对request进行处理。。最后返回一个处理后的request实例。
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    [mutableReqeust willChangeValueForKey:@"timeoutInterval"];
    mutableReqeust.timeoutInterval = 30.0f;//设置超时时间为30秒,经测试没什么用。
    [mutableReqeust didChangeValueForKey:@"timeoutInterval"];
    [NSURLProtocol setProperty:@YES
                        forKey:rainMarkKey
                     inRequest:mutableReqeust];
    return [mutableReqeust copy];
}
/*
 // 如果是，则可以使用缓存数据，通常只需要调用父类的实现即可,默认为YES,而且一般不在这里做事情
 + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b
 {
 return [super requestIsCacheEquivalent:a toRequest:b];
 }
 */

- (void)startLoading
{
    self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:YES];
    
    NSString *fileName = [self.request.URL.absoluteString lastPathComponent];
    NSString *markKey = [fileName stringByAppendingFormat:@"%@_%ld",fileName,[UrlProtocolManager shareUrlProtocolManager].requestTag];
    self.remarkKey = markKey;
    [UrlProtocolManager shareUrlProtocolManager].requestTag++;
    [[UrlProtocolManager shareUrlProtocolManager] addRequestWithRemarkKey:markKey andFileName:fileName];
    
   
}

- (void)stopLoading {
    //因为要处理失败的文件，所以就不在这里移除失败的内容了。
    [self.connection cancel];
}

#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    
    [[UrlProtocolManager shareUrlProtocolManager] removeRequestWithRemarkKey:self.remarkKey];
    //上传文件
    [self.client URLProtocol:self didFailWithError:error];
}

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection{
    return YES;
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    [self.client URLProtocol:self didReceiveAuthenticationChallenge:challenge];
}

- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [self.client URLProtocol:self didCancelAuthenticationChallenge:challenge];
}


#pragma mark - NSURLConnectionDataDelegate
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response{
    if (response != nil) {
        [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
    }
    return request;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    return cachedResponse;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
    [[UrlProtocolManager shareUrlProtocolManager] removeRequestWithRemarkKey:self.remarkKey];
    
    [[self client] URLProtocolDidFinishLoading:self];
}

@end
